package cn.datawin.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.bson.types.ObjectId;

public class ReflectUtil {

	/* 首字母大写 */
	public static String toTitleCase(String name) {
		return Character.toTitleCase(name.charAt(0)) + name.substring(1);
	}

	/* 获取setXxx的方法名称 */
	public static String toSetMethod(String name) {
		return "set" + toTitleCase(name);
	}

	/* 获取getXxx的方法名称 */
	public static String toGetMethod(String name) {
		return "get" + toTitleCase(name);
	}

	/**
	 * method.setAccessible(true); 执行方法
	 * method.invoke(obj, params...) 返回方法的执行结果, void 返回null, obj为实例[静态方法可为NULL], params 为参数,无参可为0[NULL] 
	 */
	public static Object invokeMethod(final Object object, final Method method, Object... params) {
		try {
			convert(method, params);
			return method.invoke(object, params); 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Object[] convert(final Method method, Object... params) {
		Class<?>[] _class = (Class<?>[]) method.getGenericParameterTypes(); //查找 方法形参类型
		if (_class.length != params.length){
			return params;
		}
		for (int i = 0; i < params.length; i++) {
			params[i] = covert(_class[i], params[i]);
		}
		return params;
	}
	
	/**
	 * 根据method形参转换参数,支持常用参数类型
	 * @param _class
	 * @param param
	 * @return
	 */
	public static Object covert(Class<?> _class, Object param){
		if(_class == String.class){
			return param.toString();
		}else if (_class == Integer.class || "int".equals(_class.toString())) {
			return Integer.parseInt(param.toString());
		}else if (_class == Double.class ||"double".equals(_class.toString()) ) {
			return Double.parseDouble(param.toString());
		}else if (_class == Long.class || "long".equals(_class.toString()) ) {
			return Long.parseLong(param.toString());
		}else if (_class == Float.class || "float".equals(_class.toString()) ) {
			return Float.parseFloat(param.toString());
		}else if (_class == Boolean.class || "boolean".equals(_class.toString())) {
			return Boolean.parseBoolean(param.toString());
		}else if (_class == Date.class){
			try {
				return new SimpleDateFormat("yyyy-MM-dd").parse(param.toString());
			} catch (ParseException e) {
				return param;
			}
		}
		return param;
	}

	/**
	 *  使其可见 private-->public
	 */
	protected static void makeAccessible(final Field field) {
		if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
			field.setAccessible(true);
		}
	}

	/**
	 * 持续向上查找,直到找到某个方法
	 */
	public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {
		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				return superClass.getDeclaredMethod(methodName, parameterTypes);
			} catch (NoSuchMethodException e) {// NOSONAR
				// Method不在当前类定义,继续向上转型
			}
		}
		return null;
	}

	/**
	 * 根据方法名获取方法
	 */
	public static Method getDeclaredMethod(Class<?> _class, String methodName) {
		Method m[] = _class.getMethods();
		Method me = null;
		for (int i = 0; i < m.length; i++) {
			/* 如果是公共方法,而且名称相同则返回,如果名称相同参数不同,按先后顺序只执行第一个方法 */// 是否可以判断参数个数相同的执行
			if (m[i].getModifiers() == Modifier.PUBLIC && m[i].getName().equals(methodName)) {
				me = m[i];
				break;
			}
		}
		return me;
	}

	/**
	 * 查找泛型类的泛型
	 */
	public static Class<?> getSuperClassGenricType(final Class<?> clazz, final int index) {
		Class<?> _class = Object.class;
		Type genType = clazz.getGenericSuperclass(); // 首先查找类的类型
		if (!(genType instanceof ParameterizedType)) { // 如果不是泛型类,直接返回
			return _class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); // 强制转换成泛型类的类型数组
		if (params.length == 0) {
			return _class;
		}
		try{
			/* 例如 class User<E,U> params(0)返回E,params(1)返回U */
			_class = (Class<?>) params[index];
		}catch (Exception e){
		}
		
		return _class;
	}
	
	/**
	 * 将prop 注入到 obj(CoC setName --> name)
	 */
	public static void populate(Object obj, Properties prop){
		Iterator<Object> ite = prop.keySet().iterator();
		while (ite.hasNext()) {
			String key = (String) ite.next();
			String value = prop.getProperty(key);
			String methodName = toSetMethod(key);
			Method method = getDeclaredMethod(obj.getClass(), methodName);
			invokeMethod(obj, method, value);
		}
	}
	
	/**
	 * map 转  bean<T>
	 * @param <T>
	 * @param map
	 * @param _class
	 * @return
	 */
	public static <T> T mapToBean(Map<String,?> map, Class<T> _class){
		T t;
		try {
			t = _class.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		for(String key : map.keySet()){
			Object value = map.get(key);
			String methodName = toSetMethod(key);
			Method method = getDeclaredMethod(_class, methodName);
			invokeMethod(t, method, value);
		}
		return t;
	}
	
	public static Map<String, Object> beanToMap(Object bean){
		BeanInfo info = null;
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			info = Introspector.getBeanInfo(bean.getClass());
		} catch (IntrospectionException e) {
			e.printStackTrace();
		}
		PropertyDescriptor[] pros = info.getPropertyDescriptors();
		for(PropertyDescriptor pro : pros){
			String name = pro.getName();
			if(!"class".equals(name)){
				Method method = pro.getReadMethod();
				try {
					Object result = method.invoke(bean);
					if(result!=null){
						if(ObjectId.isValid(result.toString())){
							result = new ObjectId(result.toString());
						}
						map.put(name, result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				} 
			};
		}
		return map;
	}
	

	
	/**
	 * test
	 * @param args
	 */
	public static void main(String[] args) {
		
		long q = System.currentTimeMillis();
		aa a = new aa();
		Method m = getDeclaredMethod(a.getClass(), "getName");
		invokeMethod(a, m, "2010", "nihao");
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("name", "panmg");
		map.put("age", 22);
		map.put("sex", 0);
		aa aaa=  mapToBean(map, aa.class);
		System.out.println(aaa);
		System.out.println(System.currentTimeMillis()-q);
		System.out.println(beanToMap(aaa));
	}

	static class aa {
		private String name;
		private int age ;
		private int sex ;
		
		public void getName(long name, boolean flag) {
			System.out.println("this is test!" +name+"==" + flag);
		}
		
		@Override
		public String toString() {
			return "aa [name=" + name + ", age=" + age + ", sex=" + sex + "]";
		}

		public void setName(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
		public void setAge(int age) {
			this.age = age;
		}
		public int getAge() {
			return age;
		}

		public void setSex(int sex) {
			this.sex = sex;
		}

		public int getSex() {
			return sex;
		}
	}
}
